// 版权所有2022 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package types

import "sync"

// methodList包含一系列方法，这些方法可能会被提供的
// 解析方法延迟解析。
type methodList struct {
	methods []*Func

	// guards同步惰性方法的实例化。对于lazy方法
	// 列表，guards是非零的，其长度传递给newLazyMethodList。
	// 对于非惰性方法列表，guards为零。
	guards *[]sync.Once
}

// newMethodList创建一个包含给定方法的非惰性方法列表。
func newMethodList(methods []*Func) *methodList {
	return &methodList{methods: methods}
}

// newLazyMethodList创建给定长度的惰性方法列表。方法
// 可以通过提供解析器函数，对给定的索引进行延迟解析。
func newLazyMethodList(length int) *methodList {
	guards := make([]sync.Once, length)
	return &methodList{
		methods: make([]*Func, length),
		guards:  &guards,
	}
}

// isLazy报告接收方是否是惰性方法列表。
func (l *methodList) isLazy() bool {
	return l != nil && l.guards != nil
}

// Add在方法列表中添加一个尚未出现的方法。添加
// 如果接收者懒惰，则会出现恐慌。
func (l *methodList) Add(m *Func) {
	assert(!l.isLazy())
	if i, _ := lookupMethod(l.methods, m.pkg, m.name, false); i < 0 {
		l.methods = append(l.methods, m)
	}
}

// Lookup在接收方中查找由pkg和name标识的方法。
// 如果接收者懒惰，查找就会陷入恐慌。如果foldCase为true，则如果方法名
// 与大小写折叠相等，则认为它们相等。
func (l *methodList) Lookup(pkg *Package, name string, foldCase bool) (int, *Func) {
	assert(!l.isLazy())
	if l == nil {
		return -1, nil
	}
	return lookupMethod(l.methods, pkg, name, foldCase)
}

// Len返回方法列表的长度。
func (l *methodList) Len() int {
	if l == nil {
		return 0
	}
	return len(l.methods)
}

// At返回方法列表的第i个方法。如果我不在
// 的范围内，或者如果接收者懒惰且resolve为零，则处于恐慌状态。
func (l *methodList) At(i int, resolve func() *Func) *Func {
	if !l.isLazy() {
		return l.methods[i]
	}
	assert(resolve != nil)
	(*l.guards)[i].Do(func() {
		l.methods[i] = resolve()
	})
	return l.methods[i]
}
